import 'dart:async';

import 'dart:io';

void main(){
  print('main start');
  //1、Dart是单线程模型，单线程如何完成异步
  //  1.耗时和非阻塞并不冲突，网络请求、文件读取IO、我们都可以基于非阻塞式调用
  //  2.单线程中通过事件循环来模拟异步，不断地从事件队列（Event Queue）中取出事件、并执行其对应需要执行的代码块、直到事件队列清空为止

  //2、Dart异步模型：
  //  1.Event-Looper以及Event-Queue的模型，所有的Event都是通过EventLooper的依次执行
  //  2.Dart还存在一个Microtask-Queue，用来支持一些需要优先执行的任务，而非跟EventQueue一起排队
  //  3.dart方法执行顺序是：main() -> microtask 队列（插队） -> event 队列

  //3、Dart中的异步操作：Future
  //  1.Future是为了解决“回调地狱（Callback hell）”
  //  2.Future表示一个将来会完成任务的标记
  //  3.Future有两个状态：未完成和完成，当执行耗时操作时为未完成状态，当返回一个值或者抛出一个异常为完成状态
  //  4.如果返回Future是已完成的状态，则后续如then串联的回调函数均被放到Microtask-Queue中执行,如以下：
  //立刻获取一个值，得到执行结果
  Future.value(1).then((res) {
    print('future.value run in Microtask-Queue$res');
  });
  //whenComplete一定会执行
  Future.error('error')
      .then((res) {
        print('future.error run in Microtask-Queue$res');
      })
      .catchError((error) =>
          print('future.error catchError run in Microtask-Queue $error'))
      .whenComplete(() {
        print('future.error whenComplete run in Microtask-Queue');
      });
  //future.sync传入的函数是同步运行
  //参数使用了下划线 _ ，其他语言可能表示占位符，但是在Dart中理解为占位符并不准确。应该说是习惯将 _ 视作占位符，
  // Dart只是简单的将它视作一个变量，并可以在函数中使用
  Future.sync(() => print('sync run Future')).then((_) {
    print('future.sync run in Microtask-Queue');
  });
  //  5.需要说明的是无论是then、catchError还是whenComplete，他们只是回调函数，不会加入到任何队列中
  //  4.如果返回Future是未完成的状态，则函数把自己放入Event-Queue队尾和返回一个未完成的Future对象
  //创建一个在事件队列里运行的Future:
  Future(() => print('future run in Event-Queue-1'));
  Future(() => throw 'future error in Event-Queue-2')
      .then((_) => print('Event-Queue-2 callback1'))
      .then((_) => print('Event-Queue-2 callback2'))
      .catchError((error) => print('$error'))
      .whenComplete(() => print('Event-Queue-2 whenComplete'));
  //延迟执行，Event Queue处于Idle的状态时，才会延迟1s执行，否则等待的时间会比1s长很多
  Future.delayed(const Duration(seconds: 1),
      () => print('future delayed run in Event-Queue-3'));
  Future(() => print('future error in Event-Queue -4'))
      .then((_) => print('Event-Queue-4 callback1'))
      .then((_) => print('Event-Queue-4 callback2'));
  //  6.使用wait来等待多个Future结果
  Future.wait([
    Future(() {
      print("wait future task 1");
      return 1;
    }),
    Future(() {
      print("wait future task 2");
      return 2;
    }),
    Future(() {
      print("wait future task 3");
      return 3;
    })
  ]).then((responses) {
    print(responses);
  });
  //  7.上面讲到了几个往Microtask-Queue添加任务的方法，其他往Microtask-Queue队尾添加任务的方法还有：
  //需要import 'dart:async'
  scheduleMicrotask(() {
    print('scheduleMicrotask run in Microtask-Queue');
  });
  Future.microtask(() => print('Future.microtask run in Microtask-Queue'));
  //  8.无论是往Microtask-Queue还是往Event-Queue中添加任务,都应避免Queue中任务过于繁重，
  //  否则会阻塞其他事件的处理，比如flutter中会阻塞UI,繁重任务应该使用Isolate或者Worker来执行

  //4、Dart中的异步操作：async、await
  //  1.async、await允许你像写同步代码一样写异步代码
  //  2.await标记的运算，其结果值是一个Future对象
  //  3.被async修饰的方法会同步执行其中的方法的代码直到第一个await关键字（await所在行会执行完），然后它暂停该方法其他部分的执行
  //    https://upload-images.jianshu.io/upload_images/1975877-e8edd27d15f21f24?imageMogr2/auto-orient/strip|imageView2/2/w/1200/format/webp
  //  4.一旦由awai关键字引用的Future任务执行完成，await的下一行代码将立即执行
  //  5.await必须在有async标记的函数中使用
  //  6.async函数中可以出现多个await,每遇见一个就返回一个Future, 实际结果类似于用then串起来的回调
  //  7.async函数也可以没有await, 在函数体同步执行完毕以后返回一个Future
  //  8.使用async和await还有一个好处是我们可以用和同步代码相同的try/catch机制来做异常处理
  //  9.async函数不用await调用时，返回的是Future，用await调用，可以将Future中的值取出
  Future value = async_method1();
  print('async_method1_result is ${value}');
  value.then((result){
     print('async_method1_result then is ${result}');
  });
  print('main end');
}

//执行到await async_method2()这一行时，由于async_method2很快返回了，
// 因此async_method2返回的future是完成状态，因此后续任务是在Microtask-Queue中执行的
async_method1() async {
  print('start async_method1');
  String result = await async_method2();
  sleep(const Duration(seconds: 10));
  print('end async_method1');
  return 'from async_method1 get $result';
}

async_method2() async {
  print('start async_method2');
  return "async_method2_result";
}
